﻿namespace LendLess.IPQuery
{
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;

    public class IPLocator
    {
        private byte[] data;
        private long firstStartIpOffset;
        private long ipCount;
        private long lastStartIpOffset;
        private Regex regex = new Regex(@"(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))");

        public IPLocator(string dataPath)
        {
            using (FileStream stream = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                this.data = new byte[stream.Length];
                stream.Read(this.data, 0, this.data.Length);
            }
            byte[] destinationArray = new byte[8];
            Array.Copy(this.data, 0, destinationArray, 0, 8);
            this.firstStartIpOffset = ((destinationArray[0] + (destinationArray[1] * 0x100)) + ((destinationArray[2] * 0x100) * 0x100)) + (((destinationArray[3] * 0x100) * 0x100) * 0x100);
            this.lastStartIpOffset = ((destinationArray[4] + (destinationArray[5] * 0x100)) + ((destinationArray[6] * 0x100) * 0x100)) + (((destinationArray[7] * 0x100) * 0x100) * 0x100);
            this.ipCount = Convert.ToInt64((double) (((double) (this.lastStartIpOffset - this.firstStartIpOffset)) / 7.0));
            if (this.ipCount <= 1L)
            {
                throw new ArgumentException("IP数据错误");
            }
        }
        public IPLocator( byte[] ipData)
        {
            this.data = ipData;
            byte[] destinationArray = new byte[8];
            Array.Copy(this.data, 0, destinationArray, 0, 8);
            this.firstStartIpOffset = ((destinationArray[0] + (destinationArray[1] * 0x100)) + ((destinationArray[2] * 0x100) * 0x100)) + (((destinationArray[3] * 0x100) * 0x100) * 0x100);
            this.lastStartIpOffset = ((destinationArray[4] + (destinationArray[5] * 0x100)) + ((destinationArray[6] * 0x100) * 0x100)) + (((destinationArray[7] * 0x100) * 0x100) * 0x100);
            this.ipCount = Convert.ToInt64((double)(((double)(this.lastStartIpOffset - this.firstStartIpOffset)) / 7.0));
            if (this.ipCount <= 1L)
            {
                throw new ArgumentException("IP数据错误");
            }
        }

        private string GetCountry(long endIpOff, int countryFlag, out string local)
        {
            string str = "";
            long offset = endIpOff + 4L;
            switch (countryFlag)
            {
                case 1:
                case 2:
                    str = this.GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
                    offset = endIpOff + 8L;
                    local = (1 == countryFlag) ? "" : this.GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
                    return str;
            }
            str = this.GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
            local = this.GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
            return str;
        }

        private long GetEndIp(long endIpOff, out int countryFlag)
        {
            byte[] destinationArray = new byte[5];
            Array.Copy(this.data, endIpOff, destinationArray, 0L, 5L);
            countryFlag = destinationArray[4];
            return (((Convert.ToInt64(destinationArray[0].ToString()) + (Convert.ToInt64(destinationArray[1].ToString()) * 0x100L)) + ((Convert.ToInt64(destinationArray[2].ToString()) * 0x100L) * 0x100L)) + (((Convert.ToInt64(destinationArray[3].ToString()) * 0x100L) * 0x100L) * 0x100L));
        }

        private string GetFlagStr(ref long offset, ref int countryFlag, ref long endIpOff)
        {
            int num = 0;
            byte[] destinationArray = new byte[3];
            while (true)
            {
                long sourceIndex = offset;
                sourceIndex += 1L;
                num = this.data[(int) ((IntPtr) sourceIndex)];
                if ((num != 1) && (num != 2))
                {
                    if (offset < 12L)
                    {
                        return "";
                    }
                    return this.GetStr(ref offset);
                }
                Array.Copy(this.data, sourceIndex, destinationArray, 0L, 3L);
                sourceIndex += 3L;
                if (num == 2)
                {
                    countryFlag = 2;
                    endIpOff = offset - 4L;
                }
                offset = (Convert.ToInt64(destinationArray[0].ToString()) + (Convert.ToInt64(destinationArray[1].ToString()) * 0x100L)) + ((Convert.ToInt64(destinationArray[2].ToString()) * 0x100L) * 0x100L);
            }
        }

        private long GetStartIp(long left, out long endIpOff)
        {
            long sourceIndex = this.firstStartIpOffset + (left * 7L);
            byte[] destinationArray = new byte[7];
            Array.Copy(this.data, sourceIndex, destinationArray, 0L, 7L);
            endIpOff = (Convert.ToInt64(destinationArray[4].ToString()) + (Convert.ToInt64(destinationArray[5].ToString()) * 0x100L)) + ((Convert.ToInt64(destinationArray[6].ToString()) * 0x100L) * 0x100L);
            return (((Convert.ToInt64(destinationArray[0].ToString()) + (Convert.ToInt64(destinationArray[1].ToString()) * 0x100L)) + ((Convert.ToInt64(destinationArray[2].ToString()) * 0x100L) * 0x100L)) + (((Convert.ToInt64(destinationArray[3].ToString()) * 0x100L) * 0x100L) * 0x100L));
        }

        private string GetStr(ref long offset)
        {
            byte num = 0;
            byte num2 = 0;
            StringBuilder builder = new StringBuilder();
            byte[] bytes = new byte[2];
            Encoding encoding = Encoding.GetEncoding("GB2312");
            while (true)
            {
                long num3;
                offset = (num3 = offset) + 1L;
                num = this.data[(int) ((IntPtr) num3)];
                if (num == 0)
                {
                    return builder.ToString();
                }
                if (num > 0x7f)
                {
                    offset = (num3 = offset) + 1L;
                    num2 = this.data[(int) ((IntPtr) num3)];
                    bytes[0] = num;
                    bytes[1] = num2;
                    if (num2 == 0)
                    {
                        return builder.ToString();
                    }
                    builder.Append(encoding.GetString(bytes));
                }
                else
                {
                    builder.Append((char) num);
                }
            }
        }

        private static string IntToIP(long ip_Int)
        {
            long num = (long) ((ip_Int & 0xff000000L) >> 0x18);
            if (num < 0L)
            {
                num += 0x100L;
            }
            long num2 = (ip_Int & 0xff0000L) >> 0x10;
            if (num2 < 0L)
            {
                num2 += 0x100L;
            }
            long num3 = (ip_Int & 0xff00L) >> 8;
            if (num3 < 0L)
            {
                num3 += 0x100L;
            }
            long num4 = ip_Int & 0xffL;
            if (num4 < 0L)
            {
                num4 += 0x100L;
            }
            return (num.ToString() + "." + num2.ToString() + "." + num3.ToString() + "." + num4.ToString());
        }

        private static long IpToInt(string ip)
        {
            char[] separator = new char[] { '.' };
            if (ip.Split(separator).Length == 3)
            {
                ip = ip + ".0";
            }
            string[] strArray = ip.Split(separator);
            long num = ((long.Parse(strArray[0]) * 0x100L) * 0x100L) * 0x100L;
            long num2 = (long.Parse(strArray[1]) * 0x100L) * 0x100L;
            long num3 = long.Parse(strArray[2]) * 0x100L;
            long num4 = long.Parse(strArray[3]);
            return (((num + num2) + num3) + num4);
        }

        public IPLocation Query(string ip)
        {
            if (!this.regex.Match(ip).Success)
            {
                return new IPLocation();
            }
            IPLocation location2 = new IPLocation();
            location2.IP = ip;
            long num = IpToInt(ip);
            if ((num >= IpToInt("127.0.0.1")) && (num <= IpToInt("127.255.255.255")))
            {
                location2.Country = "本机内部环回地址";
                location2.Local = "";
            }
            else if ((((num >= IpToInt("0.0.0.0")) && (num <= IpToInt("2.255.255.255"))) || ((num >= IpToInt("64.0.0.0")) && (num <= IpToInt("126.255.255.255")))) || ((num >= IpToInt("58.0.0.0")) && (num <= IpToInt("60.255.255.255"))))
            {
                location2.Country = "网络保留地址";
                location2.Local = "";
            }
            long ipCount = this.ipCount;
            long left = 0L;
            long num4 = 0L;
            long startIp = 0L;
            long endIpOff = 0L;
            long endIp = 0L;
            int countryFlag = 0;
            while (left < (ipCount - 1L))
            {
                num4 = (ipCount + left) / 2L;
                startIp = this.GetStartIp(num4, out endIpOff);
                if (num == startIp)
                {
                    left = num4;
                    break;
                }
                if (num > startIp)
                {
                    left = num4;
                }
                else
                {
                    ipCount = num4;
                }
            }
            startIp = this.GetStartIp(left, out endIpOff);
            endIp = this.GetEndIp(endIpOff, out countryFlag);
            if ((startIp <= num) && (endIp >= num))
            {
                string str;
                location2.Country = this.GetCountry(endIpOff, countryFlag, out str).Replace(" CZ88.NET", "");
                location2.Local = str.Replace(" CZ88.NET", "");
            }
            else
            {
                location2.Country = "未知";
                location2.Local = "";
            }
            location2.FullLocal = location2.Country + location2.Local;
            string country = location2.Country;
            if ((country != "") && (country != "未知"))
            {
                string[] strArray;
                string str3 = "";
                string str4 = "";
                string str5 = "";
                if (country.StartsWith("新疆"))
                {
                    strArray = SplitString(country, "新疆");
                    str3 = "新疆";
                    country = strArray[1];
                }
                else if (country.StartsWith("西藏"))
                {
                    strArray = SplitString(country, "西藏");
                    str3 = "西藏";
                    country = strArray[1];
                }
                else if (country.StartsWith("广西"))
                {
                    strArray = SplitString(country, "广西");
                    str3 = "广西";
                    country = strArray[1];
                }
                else if (country.StartsWith("宁夏"))
                {
                    strArray = SplitString(country, "宁夏");
                    str3 = "宁夏";
                    country = strArray[1];
                }
                else if (country.StartsWith("内蒙古"))
                {
                    strArray = SplitString(country, "内蒙古");
                    str3 = "内蒙古";
                    country = strArray[1];
                }
                else if (country.Contains("省"))
                {
                    strArray = SplitString(country, "省");
                    str3 = strArray[0];
                    country = strArray[1];
                }
                if (country != "")
                {
                    string[] strArray2;
                    if (country.StartsWith("北京"))
                    {
                        strArray2 = SplitString(country, "北京");
                        str4 = "北京";
                        country = strArray2[1];
                    }
                    else if (country.StartsWith("上海"))
                    {
                        strArray2 = SplitString(country, "上海");
                        str4 = "上海";
                        country = strArray2[1];
                    }
                    else if (country.StartsWith("天津"))
                    {
                        strArray2 = SplitString(country, "天津");
                        str4 = "天津";
                        country = strArray2[1];
                    }
                    else if (country.StartsWith("重庆"))
                    {
                        strArray2 = SplitString(country, "重庆");
                        str4 = "重庆";
                        country = strArray2[1];
                    }
                    else if (country.Contains("市"))
                    {
                        strArray2 = SplitString(country, "市");
                        if (strArray2.Length == 2)
                        {
                            str4 = strArray2[0];
                            country = strArray2[1];
                        }
                        else if (strArray2.Length == 3)
                        {
                            str4 = strArray2[1];
                            country = strArray2[2];
                        }
                        else
                        {
                            str4 = strArray2[2];
                            country = strArray2[3];
                        }
                    }
                }
                if ((country != "") && country.Contains("区"))
                {
                    string[] strArray3 = SplitString(country, "区");
                    str5 = strArray3[0];
                    country = strArray3[1];
                }
                location2.Province = str3;
                location2.City = str4;
                location2.District = str5;
            }
            return location2;
        }

        public static string[] SplitString(string strContent, string strSplit)
        {
            if (strContent.IndexOf(strSplit) < 0)
            {
                return new string[] { strContent };
            }
            return Regex.Split(strContent, strSplit.Replace("(", @"\(").Replace("?", @"\?").Replace(".", @"\.").Replace("|", @"\|").Replace("][", @"]\["), RegexOptions.IgnoreCase);
        }

        public long Count
        {
            get
            {
                return this.ipCount;
            }
        }
    }
}

